Use case: HAL CORDIC calculation in DMA mode with peripheral (ADC) ¶
In HAL1, to use the CORDIC peripheral together with another peripheral (such as ADC, Timer, etc.) in DMA mode, you can configure the DMA direction as follows:
CORDIC_DMA_DIR_IN
or
CORDIC_DMA_DIR_OUT
enables one-sided stream management by the CORDIC peripheral.
CORDIC_DMA_DIR_NONE
allows two peripherals to write to and read from CORDIC data registers.
In HAL2, the new functions
HAL_CORDIC_Write_DMA()
and
HAL_CORDIC_Read_DMA()
handle DMA write and read operations
separately for improved peripheral management.
In this use case, the ADC performs sampling, conversion, and writes the result directly to the
CORDIC
WDATA
register
using DMA.
The CORDIC peripheral then reads only the result. In HAL1, one-way stream management is implemented by setting the DMA
direction argument to
CORDIC_DMA_DIR_OUT. In HAL2, the read stream is managed using
HAL_CORDIC_Read_DMA()
instead.
Sequence diagram ¶
Code snippet ¶
|
HAL1 |
HAL2 |
|---|---|
#define ADC_CONVERTED_DATA_BUFFER_SIZE ((uint32_t) 32)
ADC_HandleTypeDef hadc4;
DMA_HandleTypeDef handle_GPDMA1_Channel10;
CORDIC_HandleTypeDef hcordic;
DMA_HandleTypeDef handle_GPDMA1_Channel0;
static int32_t output_data[32];
uint32_t write_addr;
ADC_ChannelConfTypeDef sConfig = {0};
hadc4.Instance = ADC4;
hadc4.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV4;
hadc4.Init.Resolution = ADC_RESOLUTION_12B;
hadc4.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc4.Init.ScanConvMode = ADC4_SCAN_DISABLE;
hadc4.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc4.Init.LowPowerAutoPowerOff = ADC_LOW_POWER_NONE;
hadc4.Init.LowPowerAutoWait = DISABLE;
hadc4.Init.ContinuousConvMode = ENABLE;
hadc4.Init.NbrOfConversion = 1;
hadc4.Init.DiscontinuousConvMode = DISABLE;
hadc4.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc4.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc4.Init.DMAContinuousRequests = ENABLE;
hadc4.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_LOW;
hadc4.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc4.Init.SamplingTimeCommon1 = ADC4_SAMPLETIME_79CYCLES_5;
hadc4.Init.SamplingTimeCommon2 = ADC4_SAMPLETIME_79CYCLES_5;
hadc4.Init.OversamplingMode = DISABLE;
HAL_ADC_Init(&hadc4);
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC4_REGULAR_RANK_1;
sConfig.SamplingTime = ADC4_SAMPLINGTIME_COMMON_1;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(&hadc4, &sConfig);
__HAL_RCC_GPDMA1_CLK_ENABLE();
handle_GPDMA1_Channel10.Instance = GPDMA1_Channel10;
handle_GPDMA1_Channel10.Init.Request = GPDMA1_REQUEST_ADC4;
handle_GPDMA1_Channel10.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
handle_GPDMA1_Channel10.Init.Direction = DMA_PERIPH_TO_MEMORY;
handle_GPDMA1_Channel10.Init.SrcInc = DMA_SINC_FIXED;
handle_GPDMA1_Channel10.Init.DestInc = DMA_DINC_FIXED;
handle_GPDMA1_Channel10.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
handle_GPDMA1_Channel10.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
handle_GPDMA1_Channel10.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel10.Init.SrcBurstLength = 1;
handle_GPDMA1_Channel10.Init.DestBurstLength = 1;
handle_GPDMA1_Channel10.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT1;
handle_GPDMA1_Channel10.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel10.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&handle_GPDMA1_Channel10);
HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
__HAL_LINKDMA(hadc, DMA_Handle, handle_GPDMA1_Channel10);
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
hcordic.Instance = CORDIC;
HAL_CORDIC_Init(&hcordic);
CORDIC_ConfigTypeDef cordic_config;
cordic_config.Function = CORDIC_FUNCTION_SINE;
cordic_config.Precision = CORDIC_PRECISION_6CYCLES;
cordic_config.Scale = CORDIC_SCALE_0;
cordic_config.NbWrite = CORDIC_NBWRITE_1;
cordic_config.NbRead = CORDIC_NBREAD_1;
cordic_config.InSize = CORDIC_INSIZE_32BITS;
cordic_config.OutSize = CORDIC_OUTSIZE_32BITS;
HAL_CORDIC_Configure(&hcordic, &cordic_config);
__HAL_RCC_GPDMA1_CLK_ENABLE()
handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
handle_GPDMA1_Channel0.Init.Request = GPDMA1_REQUEST_CORDIC_READ;
handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
handle_GPDMA1_Channel0.Init.Direction = DMA_PERIPH_TO_MEMORY;
handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_FIXED;
handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_INCREMENTED;
handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT1;
handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&handle_GPDMA1_Channel0);
HAL_NVIC_SetPriority(GPDMA1_Channel10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel10_IRQn);
__HAL_LINKDMA(hcordic, hdmaOut, handle_GPDMA1_Channel0);
/* pInBuff is set to NULL as the input data stream to the CORDIC WDATA register will be handled by the ADC,
DMADirection is set to CORDIC_DMA_DIR_OUT as HAL_CORDIC will handle only the output data stream */
HAL_CORDIC_Calculate_DMA(&hcordic, NULL, output_data, (ADC_CONVERTED_DATA_BUFFER_SIZE), CORDIC_DMA_DIR_OUT);
write_addr = (uint32_t) &(CORDIC->WDATA);
/* pData = (uint32_t *)write_addr: ADC converted values written directly to the CORDIC WDATA register */
HAL_ADC_Start_DMA(&hadc4, (uint32_t *)write_addr, (ADC_CONVERTED_DATA_BUFFER_SIZE));
/* Wait for the callbacks:
HAL_ADC_ConvCpltCallback
HAL_ADC_ErrorCallback
HAL_CORDIC_CalculateCpltCallback
HAL_CORDIC_ErrorCallback*/
|
#define OUTPUT_BUFFER_SIZE ((uint32_t) 32)
ADC_TypeDef *instance = ADC1;
hal_adc_handle_t hADC1;
hal_dma_handle_t hGPDMA1_CH0;
hal_cordic_handle_t hCORDIC;
hal_dma_handle_t hGPDMA1_CH1;
hal_adc_config_t adc_config;
hal_adc_inj_config_t adc_inj_config;
static int32_t output_data[32];
static volatile uint32_t *write_addr;
hal_cordic_buffer_desc_t output_buffer = {
.p_data = output_data,
.size_word = OUTPUT_BUFFER_SIZE};
HAL_ADC_Init(&hADC1, HAL_ADC1);
hal_adc_config_t adc_config;
adc_config.clock = HAL_ADC_CLOCK_ASYNC_DIV4;
adc_config.resolution = HAL_ADC_RESOLUTION_14_BIT;
adc_config.trigger_freq_mode = HAL_ADC_TRIGGER_FREQ_HIGH;
adc_config.sampling_mode = HAL_ADC_SAMPLING_MODE_NORMAL;
adc_config.sampling_time_com1 = HAL_ADC_SAMPLING_TIME_814CYCLES_5;
adc_config.sampling_time_com2 = HAL_ADC_SAMPLING_TIME_814CYCLES_5;
HAL_ADC_SetConfig(&hADC1, &adc_config);
hal_adc_reg_config_t reg_config;
reg_config.trigger_src = HAL_ADC_REG_TRIG_SOFTWARE_START;
reg_config.trigger_edge = HAL_ADC_REG_TRIG_EDGE_NONE;
reg_config.sequencer_length = 1;
reg_config.sequencer_discont = HAL_ADC_REG_SEQ_DISCONT_DISABLE;
reg_config.continuous = HAL_ADC_REG_CONV_CONTINUOUS;
reg_config.overrun = HAL_ADC_REG_OVR_DATA_OVERWRITTEN;
reg_config.data_transfer = HAL_ADC_REG_DATA_TRANSFER_NONE;
reg_config.sequencer_mode = HAL_ADC_REG_SEQ_FIXED;
HAL_ADC_REG_SetConfig(&hADC1, ®_config);
hal_adc_channel_config_t adc_channel_config;
adc_channel_config.group = HAL_ADC_GROUP_REGULAR;
adc_channel_config.sequencer_rank = 1;
adc_channel_config.input_mode = HAL_ADC_IN_SINGLE_ENDED;
adc_channel_config.sampling_time = HAL_ADC_SAMPLING_TIME_814CYCLES;
HAL_ADC_SetConfigChannel(&hADC1, HAL_ADC_CHANNEL_4, &adc_channel_config);
hal_adc_inj_config_t adc_inj_config;
adc_inj_config.trigger_src = HAL_ADC_INJ_TRIG_SOFTWARE_START;
adc_inj_config.trigger_edge = HAL_ADC_INJ_TRIG_EDGE_NONE;
adc_inj_config.sequencer_length = 1;
adc_inj_config.sequencer_discont = HAL_ADC_INJ_SEQ_DISCONT_DISABLE;
HAL_ADC_INJ_SetConfig(&hADC1, &adc_inj_config);
adc_channel_config.group = HAL_ADC_GROUP_INJECTED;
HAL_ADC_SetConfigChannel(&hADC1, HAL_ADC_CHANNEL_4 , &adc_channel_config);
HAL_RCC_GPDMA1_EnableClock();
HAL_DMA_Init(&hGPDMA1_CH0, HAL_GPDMA1_CH0);
hal_dma_direct_xfer_config_t xfer_cfg_adc1_dma;
xfer_cfg_adc1_dma.request = HAL_GPDMA1_REQUEST_ADC1;
xfer_cfg_adc1_dma.direction = HAL_DMA_DIRECTION_PERIPH_TO_MEMORY;
xfer_cfg_adc1_dma.src_inc = HAL_DMA_SRC_ADDR_FIXED;
xfer_cfg_adc1_dma.dest_inc = HAL_DMA_DEST_ADDR_FIXED;
xfer_cfg_adc1_dma.src_data_width = HAL_DMA_SRC_DATA_WIDTH_WORD;
xfer_cfg_adc1_dma.dest_data_width = HAL_DMA_DEST_DATA_WIDTH_WORD;
xfer_cfg_adc1_dma.priority = HAL_DMA_PRIORITY_LOW_WEIGHT_LOW;
HAL_DMA_SetConfigPeriphDirectXfer(&hGPDMA1_CH0, &xfer_cfg_adc1_dma);
HAL_CORTEX_NVIC_SetPriority(GPDMA1_CH0_IRQn, HAL_CORTEX_NVIC_PREEMP_PRIORITY_0, HAL_CORTEX_NVIC_SUB_PRIORITY_0);
HAL_CORTEX_NVIC_EnableIRQ(GPDMA1_CH0_IRQn);
HAL_ADC_REG_SetDMA(&hADC1, &hGPDMA1_CH0);
HAL_RCC_GPIOC_EnableClock();
hal_gpio_config_t gpio_config;
gpio_config.mode = HAL_GPIO_MODE_ANALOG;
gpio_config.pull = HAL_GPIO_PULL_NO;
HAL_GPIO_Init(HAL_GPIOC, HAL_GPIO_PIN_3, &gpio_config);
hal_cordic_config_t cordic_config;
HAL_CORDIC_Init(&hCORDIC, HAL_CORDIC);
HAL_RCC_CORDIC_EnableClock();
cordic_config.function = LL_CORDIC_FUNCTION_MODULUS;
cordic_config.in_width = HAL_CORDIC_IN_WIDTH_32_BIT;
cordic_config.nb_arg = HAL_CORDIC_NB_ARG_1;
cordic_config.out_width = HAL_CORDIC_OUT_WIDTH_32_BIT;
cordic_config.nb_result = HAL_CORDIC_NB_RESULT_1;
cordic_config.scaling_factor = HAL_CORDIC_SCALING_FACTOR_0;
cordic_config.precision = HAL_CORDIC_PRECISION_5_CYCLE;
HAL_CORDIC_SetConfig(&hCORDIC,&cordic_config);
HAL_RCC_GPDMA1_EnableClock();
HAL_DMA_Init(&hGPDMA1_CH1, HAL_GPDMA1_CH1);
hal_dma_direct_xfer_config_t xfer_cfg_cordic_rd_dma;
xfer_cfg_cordic_rd_dma.request = HAL_GPDMA1_REQUEST_CORDIC_RD;
xfer_cfg_cordic_rd_dma.direction = HAL_DMA_DIRECTION_PERIPH_TO_MEMORY;
xfer_cfg_cordic_rd_dma.src_inc = HAL_DMA_SRC_ADDR_FIXED;
xfer_cfg_cordic_rd_dma.dest_inc = HAL_DMA_DEST_ADDR_INCREMENTED;
xfer_cfg_cordic_rd_dma.src_data_width = HAL_DMA_SRC_DATA_WIDTH_WORD;
xfer_cfg_cordic_rd_dma.dest_data_width = HAL_DMA_DEST_DATA_WIDTH_WORD;
xfer_cfg_cordic_rd_dma.priority = HAL_DMA_PRIORITY_LOW_WEIGHT_LOW;
HAL_DMA_SetConfigPeriphDirectXfer(&hGPDMA1_CH1, &xfer_cfg_cordic_rd_dma);
HAL_CORTEX_NVIC_SetPriority(GPDMA1_CH1_IRQn, HAL_CORTEX_NVIC_PREEMP_PRIORITY_0, HAL_CORTEX_NVIC_SUB_PRIORITY_0);
HAL_CORTEX_NVIC_EnableIRQ(GPDMA1_CH1_IRQn);
HAL_CORDIC_SetReadDMA(&hCORDIC, &hGPDMA1_CH1);
/* Start reading the CORDIC output in DMA mode, while the input stream is handled by HAL_ADC */
HAL_CORDIC_Read_DMA(&hCORDIC, &output_buffer);
write_addr = HAL_CORDIC_GetWriteAddress(&hCORDIC);
HAL_ADC_Start(hADC);
/* p_data = (uint8_t const *)write_addr: ADC converted values written directly to the CORDIC WDATA register */
HAL_ADC_REG_StartConv_DMA(hADC, (uint8_t const *)write_addr, OUTPUT_BUFFER_SIZE*4);
/* Wait for the callbacks:
HAL_ADC_REG_DataTransferCpltCallback
HAL_ADC_ErrorCallback
HAL_CORDIC_CalculateCpltCallback()
HAL_CORDIC_ErrorCallback() */
|
Similarly to this use case, when using the CORDIC peripheral with a DAC in HAL1, the function
HAL_CORDIC_Calculate_DMA
is used with the
CORDIC_DMA_DIR_IN
argument. In HAL2, this is replaced by
HAL_CORDIC_Write_DMA().
Key changes ¶
HAL2 splits DMA stream management with dedicated APIs:
HAL_CORDIC_Write_DMA()andHAL_CORDIC_Read_DMA().HAL2 provides
HAL_CORDIC_GetWriteAddress()to let another peripheral (such as ADC) write directly to the CORDIC input register.HAL2 configures the CORDIC DMA streams explicitly using
HAL_CORDIC_SetReadDMA()(andHAL_CORDIC_SetWriteDMA()when needed).

